﻿//////////////////////////////////////////////////////////////////////////////
//
//  Copyright © 1998-2024 Glodon Company Limited.  All rights reserved.
//
//  Use of this software is subject to the terms of the Glodon license
//  agreement provided at the time of installation or download, or which
//  otherwise accompanies this software in either electronic or hard copy form.  
//
//////////////////////////////////////////////////////////////////////////////

// Reviewed
#pragma once
#include "GcmpActionInterface.h"

namespace gcmp
{
    class CommandParameters;
    class IUiDocument;
    class IUiView;
    class IGraphicsNodeGroup;
    class IMenuItemContainerDefinition;
    class Vector3d;

    /// \brief Action的执行结果状态
    ///
    enum class ActionFinishStatus : int32_t
    {
        Unfinished,   ///< 默认初始状态
        Successful,   ///< 成功执行完成
        Cancelled     ///< 取消状态（一般是被用户按Esc或Enter取消了）
    };

    /// \brief Action的退出原因
    ///
    enum class ActionFinishReason : int32_t
    {
        Unknown,
        Esc,          ///< 用户按Esc键
        Enter,        ///< 用户按Enter键
        RButtonDown,  ///< 用户按下鼠标右键(一般是弹出右键，只有指定右键退出才生效)
        RButtonUp,     ///< 用户弹起鼠标右键(一般是弹出右键，只有指定右键退出才生效)
        UserInputString, ///< 用户输入的字符串
        UserCustomReason  ///< 用户自定义原因
    };

    /// \brief Action返回结果数据抽象接口
    class GCMP_ACTION_INTERFACE_EXPORT IActionOutputData
    {
    public:
        virtual ~IActionOutputData() {}

        virtual OwnerPtr<IActionOutputData> Clone() const = 0;
    };

    /// \brief Action执行返回结果(执行状态/返回数据）
    struct ActionOutput
    {
        ActionOutput& operator=(const ActionOutput& src)
        {
            if (this == &src)
                return *this;

            FinishStatus = src.FinishStatus;
            FinishReason = src.FinishReason;
            InputString = src.InputString;
            ActionOutputData = nullptr;
            IsParentActionNeedCancel = src.IsParentActionNeedCancel;
            if (src.ActionOutputData)
            {
                ActionOutputData = TransferOwnership(src.ActionOutputData->Clone());
            }
            return  *this;
        }

        ActionOutput() 
            : FinishStatus(ActionFinishStatus::Unfinished)
            , FinishReason(ActionFinishReason::Unknown)
            , ActionOutputData(nullptr) 
            , IsParentActionNeedCancel(true)
        {
        }

        ActionOutput(const ActionOutput& src)
            : FinishStatus(src.FinishStatus)
            , FinishReason(src.FinishReason)
            , InputString(src.InputString)
            , ActionOutputData(nullptr)
            , IsParentActionNeedCancel(true)
        {
           if(src.ActionOutputData)
           {
               ActionOutputData = TransferOwnership(src.ActionOutputData->Clone());
           }
        }

        // 变量首字母
        ActionFinishStatus          FinishStatus = ActionFinishStatus::Unfinished; ///< 执行状态
        ActionFinishReason          FinishReason = ActionFinishReason::Unknown;
        std::wstring                InputString; ///< 原始输入字符串
        OwnerPtr<IActionOutputData> ActionOutputData; ///< 返回数据
        bool IsParentActionNeedCancel = true;   ///子Action退出时父Action是否需要退出
    };

    /// \brief Action内的视图输入类型。
    enum class ActionViewInputType : int32_t
    {
        Invalid,              //无效
        Preview_Length,       //预览长度
        Preview_Angle,        //预览角度
        Preview_Radius,       //预览半径
        Preview_Fillet,       //预览圆角弧
        Preview_CentralAngle, //预览圆心角
        Preview_Width,        //预览矩形宽度
        Preview_Height,       //预览矩形高度
        Preview_TriangleWidth,//预览三角形宽度
        Preview_TriangleHeight,//预览三角形高度
        Confirm_Length,       //确认接收长度
        Confirm_Angle,        //确认接收角度
        Confirm_Radius,       //确认接收半径
        Confirm_Fillet,       //确认接收圆角弧
        Confirm_CentralAngle, //确认接收圆心角
        Confirm_Width,        //确认接收矩形宽度
        Confirm_Height,       //确认接收矩形高度
        Confirm_TriangleWidth, //确认接收三角形宽度
        Confirm_TriangleHeight,//确认接收三角形高度
    };

    /// \brief Action视图输入数据抽象接口
    class IActionViewInputData
    {
    public:
        virtual ~IActionViewInputData() {}
    };

    /// \brief Action内的视图输入数据
    struct ActionViewInput
    {
        ActionViewInput() : ActionInputData(nullptr)
        {
            InputType = ActionViewInputType::Invalid;
            InputVal = 0.0;
        }

        ActionViewInput(ActionViewInputType type, double val)
        {
            InputType = type;
            InputVal = val;
        }

        ActionViewInputType InputType;
        double              InputVal; ///< 输入数据
        std::wstring        InputString; ///< 原始输入字符串
        gcmp::OwnerPtr<IActionViewInputData> ActionInputData; ///< 用户扩展的输入数据
    };

    /// \brief action完成时状态类型
    enum class ActionFinishedMode : int32_t
    {
        LButtonDown = 0, ///< 鼠标左键按下
        LButtonUp = 1,   ///< 鼠标左键按下后弹起
        RButtonDown = 2, ///< 鼠标右键按下
        RButtonUp = 3  ///< 鼠标右键按下后弹起
    };

    /// \brief Action是一种用户交互对象，用于实现各种基于用户输入的业务逻辑。
    class GCMP_ACTION_INTERFACE_EXPORT IAction
    {
    public:
        virtual ~IAction() {}

        // 对用户输入事件的响应
    public:
        /// \brief Action被启动后，接收任何用户输入之前，该方法会被调用。
        /// \param pCurrentView 执行Action当前视图
        /// \return void
        virtual void InitAction(IUiView* pCurrentView) = 0;

        /// \brief Action被强制退出时（比如用户按了Esc键，或者点击了其它同级别的命令），该方法会被调用。
        /// \return void
        virtual void ActionCancelled() = 0;

        /// \brief 获取Action执行的返回参数,含执行状态和数据
        /// \param param 执行Action的状态和数据
        /// \return void
        virtual void GetActionOutput(ActionOutput& param) const = 0;

        /// \brief 鼠标左键按下事件处理
        /// \param pCurrentView 当前视图
        /// \param pos 鼠标位置
        /// \return 返回值为true表示已处理，false表示未处理。（系统会根据该返回值决定是否把消息传递到下一个接收者）
        virtual bool OnLButtonDown(IUiView* pCurrentView, const Vector3d& pos) = 0;

        /// \brief 鼠标左键弹起事件处理
        /// \param pCurrentView 当前视图
        /// \param pos 鼠标位置
        /// \return 返回值为true表示已处理，false表示未处理。（系统会根据该返回值决定是否把消息传递到下一个接收者）
        virtual bool OnLButtonUp(IUiView* pCurrentView, const Vector3d& pos) = 0;

        /// \brief 鼠标左键双击事件处理
        /// \param pCurrentView 当前视图
        /// \param pos 鼠标位置
        /// \return 返回值为true表示已处理，false表示未处理。（系统会根据该返回值决定是否把消息传递到下一个接收者）
        virtual bool OnLButtonDoubleClick(IUiView* pCurrentView, const Vector3d& pos) = 0;

        /// \brief 鼠标右键按下事件处理
        /// \param pCurrentView 当前视图
        /// \param pos 鼠标位置
        /// \return 返回值为true表示已处理，false表示未处理。（系统会根据该返回值决定是否把消息传递到下一个接收者）
        virtual bool OnRButtonDown(IUiView* pCurrentView, const Vector3d& pos) = 0;

        /// \brief 鼠标右键弹起事件处理
        /// \param pCurrentView 当前视图
        /// \param pos 鼠标位置
        /// \return 返回值为true表示已处理，false表示未处理。（系统会根据该返回值决定是否把消息传递到下一个接收者）
        virtual bool OnRButtonUp(IUiView* pCurrentView, const Vector3d& pos) = 0;

        /// \brief 鼠标移动事件处理
        /// \param pCurrentView 当前视图
        /// \param pos 鼠标位置
        /// \return 返回值为true表示已处理，false表示未处理。（系统会根据该返回值决定是否把消息传递到下一个接收者）
        virtual bool OnMovePoint(IUiView* pCurrentView, const Vector3d& pos) = 0;

        /// \brief 键盘按下事件处理
        /// \param pCurrentView 当前视图
        /// \param nChar 键盘键值
        /// \return 返回值为true表示已处理，false表示未处理。（系统会根据该返回值决定是否把消息传递到下一个接收者）
        virtual bool OnKeyDown(IUiView* pCurrentView, int nChar) = 0;

        /// \brief 按健弹起事件处理
        /// \param pCurrentView 当前视图
        /// \param nChar 键盘键值
        /// \return 返回值为true表示已处理，false表示未处理。
        virtual bool OnKeyUp(IUiView* pCurrentView, int nChar) = 0;

        /// \brief 视图内输入事件处理
        /// \param pCurrentView 当前视图
        /// \param inputData 输入参数（含输入类型和数据）
        /// \return 返回值为true表示已处理，false表示未处理
        virtual bool OnReceiveViewInputData(IUiView* pCurrentView, const ActionViewInput& inputData) = 0;

        /// \brief 当用户点击一个界面按钮或菜单项执行命令时，该方法会被调用。
        /// \param pCurrentView 当前视图
        /// \param idString 命令Id
        /// \param cmdParams 命令参数
        /// \return 返回值为true表示已处理，false表示未处理
        virtual bool OnCommand(IUiView* pCurrentView, const std::wstring& idString, const CommandParameters& cmdParams) = 0;
 

        /// \brief 当视图被切换后，该方法会被调用（使用前提Action支持跨视图，跨视图Action需要同时重载PreviewViewSwitch()）。
        /// \param pUIView 切换后的新视图
        /// \return 返回值为true表示已处理，false表示未处理
        virtual bool OnViewSwitched(IUiView* pUIView) = 0;

        /// \brief 如果子类存在跨视图行为，需要重载这个函数，同时重载OnViewSwitched(IUiView* pUIView)
        /// \return 返回true表示支持视图切换(默认支持视图切换，但切换视图取消当前Action)
        virtual bool PreviewViewSwitched() = 0;


        /// \brief 当该Action之上的子Action结束后，该方法会被调用。
        /// \param pCurrentView 执行Action当前视图
        /// \param childActionReturnParam 子Action完成时的状态和数据参数
        /// \return 
        virtual void OnChildActionFinished(IUiView* pCurrentView, const ActionOutput& childActionReturnParam) = 0;


        /// \brief 获取Action光标
        /// \param void
        /// \return 光标资源路径
        virtual std::wstring GetCursorPath() const = 0;

        /// \brief 获取Action当前鼠标状态提示
        /// \return 返回鼠标提示信息
        virtual std::wstring GetMouseTooltipMessage() const = 0;


        /// \brief 设置Action鼠标右键上下文菜单
        /// \param pUIView 当前视图
        /// \return 上下文菜单项列表
        virtual OwnerPtr<IMenuItemContainerDefinition> PrepareContextMenu(IUiView* pUIView) = 0;

        /// \brief 获取Action当前的当前状态提示字符串
        /// \return Action当前状态提示信息
        virtual std::wstring GetPromptMessage() const = 0;
        
        /// \brief 获取当前Action接受输入长度参数有效范围。
        /// \param minLen 有效最小长度
        /// \param maxLen 有效最大长度
        /// \return 
        virtual void GetValidRangeOfLength(double& minLen /*= gcmp::MIN_MODEL_SIZE*/, double& maxLen /*= gcmp::Constants::MAX_MODEL_SIZE*/) const = 0;
        
        /// \brief 获取当前Action接受输入角度参数有效范围。
        /// \param minLen 有效最小角度
        /// \param maxLen 有效最大角度
        /// \return 
        virtual void GetValidRangeOfAngle(double& minAng /*= -180*/, double& maxAng /*= 180*/) const = 0;
      

        /// \brief  重载此方法以告知系统,是否在顶层Action处理键盘事件前先预览并处理键盘相关事件。
        /// \return 默认返回false，返回true表示支持预处理，false不支持
        virtual bool PreviewKeyEvent() = 0;
        
        /// \brief  重载此方法以告知系统,是否在顶层Action处理鼠标事件前先预览并处理鼠标相关事件。
        /// \return 默认返回false，返回true表示支持预处理，false不支持
        virtual bool PreviewMouseEvent() = 0;
        
        /// \brief  重载此方法以告知系统,是否在顶层Action处理命令事件前先预览并处理命令相关事件。
        /// \return 默认返回false，返回true表示支持预处理，false不支持
        virtual bool PreviewCommand() = 0;

        /// \brief 获取当前Action的启动路径
        /// \return 返回Action启动的command 路径，最后一个是启动当前Action的command
        virtual const std::list<std::wstring>& CommandChain() const = 0;

        //////////////////////////////////////////////////////////////////////////
        /// \brief 暂时保留,用于保存文档时记录启动Action的命令，完成后恢复到当前Action
        /// \param commandId 启动这个action的command Id。
        virtual void SetCommandId(const std::wstring &commandId) = 0;
        /// \brief 暂时保留,用于保存文档时记录启动Action的命令，完成后恢复到当前Action
        virtual std::wstring GetCommandId() const = 0;

        /// \brief 暂时保留 回调, 根据当前的视图输入状态, 刷新视图内的临时对象（视图内输入是重定位点需要）
        virtual bool OnMoveCallback(IUiView* pCurrentView) = 0;

        //////////////////////////////////////////////////////////////////////////
        /// \brief TODO：这个方法去掉工作量巨大，暂时搁置保留，注意：请勿使用！！请勿使用！！！
        /// \return pUIDoc 设置Action对应的文档
        virtual void SetUiDocument(gcmp::IUiDocument* pUIDoc) = 0;
        //////////////////////////////////////////////////////////////////////////

  
    };

}
